/*
 * Copyright 2008 Nathan C Jones
 * 
 * This file is part of Fivehundred.
 * 
 * Fivehundred is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Fivehundred is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * Fivehundred. If not, see <http://www.gnu.org/licenses/>. 
 */

package com.googlecode.fivehundred.ui;

import java.awt.AWTEventMulticaster;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

/**
 * Skeletal implementation of a GraphicalComponent.
 * 
 * @author Nathan C Jones
 */
public abstract class AbstractGraphicalComponent implements GraphicalComponent {

	/** The root mouse listener. */
	private MouseListener mouseListener = null;

	private MouseMotionListener mouseMotionListener = null;

	/** The parent component. */
	private CompositeGraphicalComponent parent;

	/** The horizontal position of the component. */
	private int x = 0;

	/** The vertical position of the component. */
	private int y = 0;

	/** The angle of the component. */
	private double angle = 0.0;

	@Override
	public void addMouseListener(MouseListener listener) {
		this.mouseListener = AWTEventMulticaster.add(this.mouseListener, listener);
	}

	public void addMouseMotionListener(MouseMotionListener listener) {
		this.mouseMotionListener = AWTEventMulticaster.add(this.mouseMotionListener, listener);
	}

	/**
	 * {@inheritdoc}
	 */
	@Override
	public void processMouseEvent(MouseEvent event) {
		if (event == null) {
			throw new IllegalArgumentException("Cannot process a null event.");
		}
		final MouseListener listener = this.mouseListener;
		if (listener != null) {
			final int id = event.getID();
			switch (id) {
				case MouseEvent.MOUSE_PRESSED:
					listener.mousePressed(event);
					break;
				case MouseEvent.MOUSE_RELEASED:
					listener.mouseReleased(event);
					break;
				case MouseEvent.MOUSE_CLICKED:
					listener.mouseClicked(event);
					break;
				case MouseEvent.MOUSE_EXITED:
					listener.mouseExited(event);
					break;
				case MouseEvent.MOUSE_ENTERED:
					listener.mouseEntered(event);
					break;
				case MouseEvent.MOUSE_MOVED:
					mouseMotionListener.mouseMoved(event);
					break;
			}
		}
	}

	/**
	 * {@inheritdoc}
	 */
	@Override
	public void removeMouseListener(MouseListener listener) {
		this.mouseListener = AWTEventMulticaster.remove(this.mouseListener, listener);
	}

	/**
	 * {@inheritdoc}
	 */
	@Override
	public Point getPosition() {
		return new Point(x, y);
	}

	/**
	 * {@inheritdoc}
	 */
	@Override
	public CompositeGraphicalComponent getParent() {
		return parent;
	}

	/**
	 * {@inheritdoc}
	 */
	@Override
	public void setParent(CompositeGraphicalComponent parent) {
		this.parent = parent;
	}

	/**
	 * {@inheritdoc}
	 */
	@Override
	public void setPosition(int x, int y) {
		// FIXME this is probably wrong. need to determine how to ensure x and y
		// are not read when only one of them has been updated.
		synchronized (this) {
			this.x = x;
			this.y = y;
		}
	}

	/**
	 * {@inheritdoc}
	 */
	public double getAngle() {
		return angle;
	}

	/**
	 * {@inheritdoc}
	 */
	public void setAngle(double angle) {
		this.angle = angle;
	}

	/**
	 * {@inheritdoc}
	 */
	public Point getAbsolutePosition() {
		final CompositeGraphicalComponent parent = getParent();
		if (parent == null) {
			throw new IllegalStateException("Component has no parent.");
		}
		final Point parentPosition = parent.getAbsolutePosition();
		final Point position = getPosition();
		return new Point(parentPosition.x + position.x, parentPosition.y + position.y);
	}

	public double getAbsoluteAngle() {
		final CompositeGraphicalComponent parent = getParent();
		if (parent == null) {
			throw new IllegalStateException("Component has no parent.");
		}
		return getAngle() + parent.getAbsoluteAngle();
	}
}
